package com.adee.java;

import java.util.LinkedList;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/*
* ReentrantLock中的公平锁和非公平锁
* 首先不管是公平锁还是非公平锁，它们的底层都是使用AQS来进行排队，它们的区别在于线程在使用lock()方法加锁时，如果是公平锁，会先检查AQS队列
* 中是否有正在排队的线程，如果有，则当前线程进入线程队列排队，如果是非公平锁，则不会去检查是否有线程在排队等待获取该锁，而是直接参与竞争，尝
* 试获取锁，尝试一次获取不到后，再去排队。
* 不管是公平锁还是非公平锁，一旦没有竞争到锁，都会进行排队，当锁释放时，都是唤醒排在最前面的线程，所以非公平锁只是体现在了线程加锁阶段，没有
* 体现在线程被唤醒的阶段。
*
* */
public class Test024_ReentrantLock {
    static int cnt = 0;
    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        // test1();
        test2();
    }

    /*
    * ReentrantLock普通用法
    * */
    public static void test1() throws InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CountDownLatch latch = new CountDownLatch(100);
        for (int i = 0; i < 100; i++) {
            threadPool.submit(() -> {
                lock.lock();
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                    cnt++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                    latch.countDown();
                }
            });
        }
        latch.await();
        System.out.println("cnt: " + cnt);
    }

    /*
    * 使用ReentrantLock+Condition实现生产者消费者模式
    * */
    public static void test2() {
        ExecutorService producers = Executors.newFixedThreadPool(3);
        ExecutorService consumers = Executors.newFixedThreadPool(3);
        ReentrantLock lock = new ReentrantLock();
        Condition notEmpty = lock.newCondition();
        Condition notFull = lock.newCondition();
        LinkedList<Integer> goods = new LinkedList<>();
        final int CAP = 10;
        // 生产
        for (int i = 0; i < 3; i++) {
            producers.submit(() -> {
                for (;;) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock.lock();
                    try {
                        while(goods.size() == CAP) { // 满了
                            notFull.await();
                        }
                        Integer n = ThreadLocalRandom.current().nextInt(1000);
                        goods.add(n);
                        System.out.println(">>> 生产 " + n);
                        notEmpty.signal();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            });
        }

        // 消费
        for (int i = 0; i < 3; i++) {
            consumers.submit(() -> {
                for (;;) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock.lock();
                    try {
                        while(goods.isEmpty()) { // 空了
                            notEmpty.await();
                        }
                        Integer n = goods.removeFirst();
                        System.out.println(">>> 消费 " + n);
                        notFull.signal();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            });
        }

    }
}
